package org.one.onecat;

import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.HttpRequest;
import org.one.disruptor.MessageConsumer;
import org.one.entity.TranslatorDataWrapper;
import org.one.servlet.OneRequest;
import org.one.servlet.OneResponse;
import org.one.servlet.OneServlet;
import org.one.servlet.impl.DefaultOneServlet;
import org.one.servlet.impl.HttpOneRequest;
import org.one.servlet.impl.HttpOneResponse;

import java.io.File;
import java.net.URL;
import java.util.Map;


/**
 * @Classname : OneCatMessageConsumer
 * @Description : 消费者OneCat实现类
 * @Author : cty
 * @Date 2023/6/11 22:59
 */


public class OneCatMessageConsumer extends MessageConsumer {

    // 操作系统识别的换行符
    private static final String CR = System.getProperty("line.separator");


    public OneCatMessageConsumer(String consumerId) {
        super(consumerId);
    }

    @Override
    public void onEvent(TranslatorDataWrapper dataWrapper) throws Exception {
        Object msg = dataWrapper.getMsg();
        ChannelHandlerContext ctx = dataWrapper.getCtx();
        Map<String, String> nameToClassNameMap = dataWrapper.getNameToClassNameMap();
        Map<String, OneServlet> nameToServletMap = dataWrapper.getNameToServletMap();

        if (msg instanceof HttpRequest) {
            HttpRequest request = (HttpRequest) msg;
            String uri = request.uri();

            // 先进行静态资源判断
            String filePath = uri.substring(1);
            URL fileUrl = this.getClass().getClassLoader().getResource(filePath);
            if (fileUrl != null) {
                File reqFile = new File(fileUrl.getFile());
                OneResponse res = new HttpOneResponse(request, ctx);
                if (reqFile.exists() && reqFile.isFile()) {
                    res.write(reqFile);
                } else {
                    res.write(new File(this.getClass().getClassLoader().getResource("404.html").getFile()));
                }
            }
             else {
                // 从请求中解析出要访问的Servlet名称
                // aaa/bbb/twoservlet?name=aa
                String servletName = "";
                if (uri.contains("/")) {
                    servletName = uri.substring(uri.lastIndexOf("/") + 1);
                }
                if (servletName.contains(".do") || servletName.contains(".action")) {
                    servletName= servletName.substring(0, servletName.indexOf("."));
                }
                if (servletName.contains("?")){
                    servletName= servletName.substring(0, servletName.indexOf("?"));
                }

                OneServlet servlet = new DefaultOneServlet();
                //第一次访问，Servlet是不会被加载的
                //初始化加载的只是类全限定名称，懒加载
                //如果访问Servlet才会去初始化它对象
                if (nameToServletMap.containsKey(servletName)) {
                    servlet = nameToServletMap.get(servletName);
                } else if (nameToClassNameMap.containsKey(servletName)) {
                    // double-check，双重检测锁：为什么要在锁前判断一次，还要在锁后继续判断一次？
                    // 锁前判断一次：若对象已经存在，则无需排队获取锁
                    if (nameToServletMap.get(servletName) == null) {
                        synchronized (this) {
                            // 锁后继续判断一次：获取锁后，有可能对象已经被创建
                            if (nameToServletMap.get(servletName) == null) {
                                // 获取当前Servlet的全限定性类名
                                String className = nameToClassNameMap.get(servletName);
                                // 使用反射机制创建Servlet实例
                                servlet = (OneServlet) Class.forName(className).newInstance();
                                // 将Servlet实例写入到nameToServletMap
                                nameToServletMap.put(servletName, servlet);
                            }
                        }
                    }
                } //  end-else if

                // 代码走到这里，servlet肯定不空
                OneRequest req = new HttpOneRequest(request);
                OneResponse res = new HttpOneResponse(request, ctx);
                // 根据不同的请求类型，调用servlet实例的不同方法
                if (request.method().name().equalsIgnoreCase("GET")) {
                    servlet.doGet(req, res);
                } else if(request.method().name().equalsIgnoreCase("POST")) {
                    servlet.doPost(req, res);
                }
            }
            ctx.close();
        }
    }
}
